package org.c41.graphics.render;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.event.KeyListener;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferStrategy;

import javax.swing.JFrame;

import org.c41.graphics.C41Graphic;
import org.c41.graphics.effect.Paintable;
import org.c41.graphics.effect.Updatable;
import org.c41.system.C41System;

public class JRenderFrame{
	 
	private final C41JRenderFrame frame;
	private RenderHandler handler;
	
	public JRenderFrame(){
		frame=new C41JRenderFrame();
	}
	
	public JRenderFrame(int width, int height){
		frame=new C41JRenderFrame(width,height);
	}
	
	public void setFps(int fps){
		this.frame.setFps(fps);
	}
	
	public int getFps(){
		return frame.getFps();
	}
	
	public void setPainter(Paintable painter){
		frame.setPainter(painter);
	}
	
	public Paintable getPainter(){
		return frame.getPainter();
	}
	
	public void show(){
		frame.setVisible(true);
		frame.startPainting();
	}
	
	public void hide(){
		frame.stopPainting();
		frame.setVisible(false);
	}
	
	public void dispose(){
		frame.stopPainting();
		frame.dispose();
	}
	
	public void setSize(int width, int height){
		frame.setSize(width,height);
	}
	
	public void setLocation(int x, int y){
		frame.setLocation(x, y);
	}
	
	public int getWidth(){
		return frame.getWidth();
	}
	
	public int getHeight(){
		return frame.getHeight();
	}
	
	public int getX(){
		return frame.getX();
	}
	
	public int getY(){
		return frame.getY();
	}
	
	public RenderHandler getHandler(){
		return this.handler;
	}
	
	public void setHandler(RenderHandler handler){
		if(this.handler==handler){
			return;
		}
		if(this.handler!=null){
			this.frame.removeMouseListener(handler);
			this.frame.removeMouseMotionListener(handler);
			this.frame.removeKeyListener(handler);
		}
		this.handler=handler;
		if(this.handler!=null){
			this.frame.addMouseListener(handler);
			this.frame.addMouseMotionListener(handler);
			this.frame.addKeyListener(handler);
		}
	}
	
	public int getPaintingWidth(){
		return frame.getPaintingWidth();
	}
	
	public int getPaintingHeight(){
		return frame.getPaintingHeight();
	}
	
	public boolean isPainting(){
		return this.frame.isRunning();
	}
	
	public void setUpdater(Updatable updater){
		this.frame.setUpdater(updater);
	}
	
	public Updatable getUpdater(){
		return this.frame.getUpdater();
	}
	
}

class C41JRenderFrame extends JFrame {

	private RenderView view = new RenderView();
	private boolean is_running;
	private FPSTimer timer;
	private Paintable painter;
	private Updatable updater;
	
	public C41JRenderFrame(){
		this(800, 600);
	}
	
	public C41JRenderFrame(int width, int height){
		setLayout(new GridLayout(1,1));
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		getContentPane().add(view);
		setIgnoreRepaint(true);
		setResizable(false);
		requestFocus();
		pack();
		setSize(width, height);
		setLocationRelativeTo(null);
		view.createBufferStrategy();
		timer = new FPSTimer(50);
	}
	
	public int getFps(){
		return timer.getFps();
	}
	
	public void setFps(int fps){
		timer = new FPSTimer(fps);
	}
	
	public void setPainter(Paintable painter){
		this.painter=painter;
	}
	
	public Paintable getPainter(){
		return this.painter;
	}
	
	public int getPaintingWidth(){
		return this.view.getWidth();
	}
	
	public int getPaintingHeight(){
		return this.view.getHeight();
	}
	
	public void startPainting(){
		if(is_running){
			return;
		}
		this.is_running=true;
		C41System.createThread(view);
	}
	
	public boolean isRunning(){
		return this.is_running;
	}
	
	public void stopPainting(){
		this.is_running=false;
	}
	
	@Override
	public void addMouseListener(MouseListener l){
		this.view.addMouseListener(l);
	}
	
	@Override
	public void removeMouseListener(MouseListener l){
		this.view.removeMouseListener(l);
	}
	
	@Override
	public void addKeyListener(KeyListener l){
		this.view.addKeyListener(l);
	}
	
	@Override
	public void removeKeyListener(KeyListener l){
		this.view.removeKeyListener(l);
	}
	
	@Override
	public void addMouseMotionListener(MouseMotionListener l){
		this.view.addMouseMotionListener(l);
	}
	
	@Override
	public void removeMouseMotionListener(MouseMotionListener l){
		this.view.removeMouseMotionListener(l);
	}
	
	public void setUpdater(Updatable updater){
		this.updater=updater;
	}
	
	public Updatable getUpdater(){
		return this.updater;
	}
	
	private class RenderView extends Canvas implements Runnable{
		
		private BufferStrategy strategy;
		
		public RenderView(){
			setBackground(Color.BLACK);
			setIgnoreRepaint(true);
		}

		private void createBufferStrategy() {
			createBufferStrategy(2);
			this.strategy = getBufferStrategy();
		}
		
		@Override
		public void run() {
			while (is_running) {
				timer.update();
				if(updater!=null){
					updater.update(timer.getSpacingTime());
				}
				Graphics2D graphics = (Graphics2D)this.strategy.getDrawGraphics();
				C41Graphic c41graphic = new C41Graphic(graphics);
				if(painter!=null){
					painter.paint(c41graphic);
				}
				c41graphic.dispose();
				this.strategy.show();
				timer.pause();
			}
		}
		
	}
	
}
